default_platform :android
skip_docs

require 'json'
require 'net/http'
import 'Allurefile'

github_repo = ENV['GITHUB_REPOSITORY'] || 'GetStream/stream-chat-android'
test_flavor = 'stream-chat-android-compose-sample'
mock_server_driver_port = 4567
is_localhost = !is_ci
@force_check = false

before_all do |lane|
  if is_ci
    setup_ci
    setup_git_config
  end
end

lane :start_mock_server do |options|
  mock_server_repo = 'stream-chat-test-mock-server'
  stop_mock_server if is_localhost

  if options[:local_server]
    mock_server_repo = options[:local_server]
  else
    sh("rm -rf #{mock_server_repo}") if File.directory?(mock_server_repo)
    sh("git clone https://github.com/#{github_repo.split('/').first}/#{mock_server_repo}.git")
  end

  Dir.chdir(mock_server_repo) do
    FileUtils.mkdir_p('logs')
    sh("bundle exec ruby driver.rb > logs/driver.log 2>&1 &")
  end
end

lane :stop_mock_server do
  Net::HTTP.get_response(URI("http://localhost:#{mock_server_driver_port}/stop")) rescue nil
end

lane :run_sonar_analysis do |options|
  next unless is_check_required(sources: sources_matrix[:sonar], force_check: @force_check)

  Dir.chdir('..') { sh('./gradlew sonar') }
end

lane :run_snapshot_test do |options|
  next unless is_check_required(sources: sources_matrix[:ui], force_check: @force_check)

  cmd = [
    './gradlew',
    'stream-chat-android-ui-uitests:executeScreenshotTests',
    '-Pandroid.testInstrumentationRunnerArguments.filter=io.getstream.chat.android.uitests.util.SnapshotTestFilter',
    '-Dorg.gradle.jvmargs="--add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/java.nio.channels=ALL-UNNAMED --add-exports java.base/sun.nio.ch=ALL-UNNAMED"'
  ]
  cmd << '-Precord' unless options[:record].to_s.empty?
  Dir.chdir('..') { sh(cmd.join(' ')) }
end

lane :build_and_run_e2e_test do |options|
  build_e2e_test
  run_e2e_test(batch: options[:batch], batch_count: options[:batch_count], local_server: options[:local_server])
end

lane :build_e2e_test do
  next unless is_check_required(sources: sources_matrix[:e2e], force_check: @force_check)

  gradle(
    tasks: [":#{test_flavor}:assembleE2eDebugAndroidTest", ":#{test_flavor}:assembleE2eDebug"],
    flags: "--scan"
  )
end

lane :run_e2e_test do |options|
  next unless is_check_required(sources: sources_matrix[:e2e], force_check: @force_check)

  allure_results_path = 'allure-results'
  adb_test_results_path = '/sdcard/googletest/test_outputfiles'
  sh("rm -rf #{allure_results_path}")
  sh("adb shell rm -rf #{adb_test_results_path}/#{allure_results_path}")

  start_mock_server(local_server: options[:local_server])
  install_test_services
  upload_attachments

  stream_apk_folder_path = is_ci ? '..' : "../#{test_flavor}/build/outputs/apk"
  stream_app_path = "#{stream_apk_folder_path}/e2e/debug/stream-chat-android-compose-sample-e2e-debug.apk"
  stream_test_path = "#{stream_apk_folder_path}/androidTest/e2e/debug/stream-chat-android-compose-sample-e2e-debug-androidTest.apk"
  sh("adb install -r #{stream_app_path}")
  sh("adb install -r #{stream_test_path}")

  app_package_name = 'io.getstream.chat.android.compose.sample.e2etest.debug'
  test_package_name = "#{app_package_name}.test"
  runner_package_name = 'io.qameta.allure.android.runners.AllureAndroidJUnitRunner'
  orchestrator_package_name = 'androidx.test.orchestrator/.AndroidTestOrchestrator'
  androidx_test_services_path = sh('adb shell pm path androidx.test.services').strip

  run_tests_in_batches = batch_tests(
    batch: options[:batch],
    batch_count: options[:batch_count],
    test_apk_path: stream_test_path
  )

  result = sh(
    "adb shell 'CLASSPATH=#{androidx_test_services_path}' " \
    'app_process / androidx.test.services.shellexecutor.ShellMain am instrument -w -e clearPackageData true ' \
    "-e targetInstrumentation #{test_package_name}/#{runner_package_name} #{run_tests_in_batches} #{orchestrator_package_name}"
  )

  sh("adb exec-out sh -c 'cd #{adb_test_results_path} && tar cf - #{allure_results_path}' | tar xvf - -C .") if is_ci
  stop_mock_server

  UI.user_error!('Tests have failed!') if result.include?('Failures')
end

# This lane can be used for local linting
lane :lint_e2e_test do |options|
  Dir.chdir('..') do
    ['stream-chat-android-e2e-test', 'stream-chat-android-compose-sample'].each do |target|
      sh("./gradlew :#{target}:spotlessApply :#{target}:detekt")
    end
  end
end

lane :upload_attachments do
  ['png', 'pdf'].each do |ext|
    [1, 2].each { |i| sh("adb push attachments/file.#{ext} /sdcard/Download/file_#{i}.#{ext}") }
  end
end

private_lane :batch_tests do |options|
  if options[:batch] && options[:batch_count]
    install(tool: :test_parser)
    sh("java -jar test-parser.jar #{options[:test_apk_path]} ./")
    test_names = File.read('AllTests.txt').split
    current_batch = test_names.each_slice((test_names.size.to_f / options[:batch_count].to_i).ceil).to_a[options[:batch].to_i]
    "-e class #{current_batch.join(',')}"
  else
    ''
  end
end

private_lane :install_test_services do
  FileUtils.mkdir_p('apks')
  device_api_level = sh('adb shell getprop ro.build.version.sdk').strip.to_i
  install(tool: :test_orchestrator, api_level: device_api_level)
  install(tool: :test_services, api_level: device_api_level)
  install(tool: :allurectl, chmod: true) if is_ci
end

desc 'Run fastlane linting'
lane :rubocop do
  next unless is_check_required(sources: sources_matrix[:ruby], force_check: @force_check)

  sh('bundle exec rubocop')
end

private_lane :sources_matrix do
  {
    unit: ['stream-chat-android-test', 'stream-chat-android-client', 'stream-chat-android-compose/', 'stream-chat-android-core', 'stream-chat-android-markdown-transformer', 'stream-chat-android-offline', 'stream-chat-android-state', 'stream-chat-android-ui-common', 'stream-chat-android-ui-components/', 'stream-chat-android-ui-utils/'],
    ui: ['stream-chat-android-ui', '.github/workflows/snapshot-test'],
    e2e: ['buildSrc', 'stream-chat-android', '.github/workflows/e2e-test'],
    sonar: ['stream-chat-android-client/', 'stream-chat-android-compose/', 'stream-chat-android-core/', 'stream-chat-android-markdown-transformer/', 'stream-chat-android-offline/', 'stream-chat-android-state/', 'stream-chat-android-ui-common/', 'stream-chat-android-ui-components/', 'stream-chat-android-ui-utils/'],
    ruby: ['fastlane', 'Gemfile', 'Gemfile.lock']
  }
end

private_lane :install do |options|
  case options[:tool]
  when :test_orchestrator
    v = '1.5.1'
    output = 'apks/orchestrator.apk'
    url = "https://dl.google.com/dl/android/maven2/androidx/test/orchestrator/#{v}/orchestrator-#{v}.apk"
  when :test_services
    v = '1.5.0'
    output = 'apks/test-services.apk'
    url = "https://dl.google.com/dl/android/maven2/androidx/test/services/test-services/#{v}/test-services-#{v}.apk"
  when :test_parser
    v = '2.2.1'
    output = 'test-parser.jar'
    url = "https://linkedin.jfrog.io/artifactory/open-source/com/linkedin/dextestparser/parser/#{v}/parser-#{v}-all.jar"
  when :allurectl
    v = '2.16.0'
    output = 'allurectl'
    arch = RbConfig::CONFIG['host_os'].include?('darwin') ? 'darwin_amd64' : 'linux_amd64'
    url = "https://github.com/allure-framework/allurectl/releases/download/#{v}/allurectl_#{arch}"
  else
    UI.user_error!('Provide a correct tool name.')
  end
  sh("wget -O #{output} '#{url}' 2>/dev/null") unless File.exist?(output)
  sh("adb install #{options[:api_level] >= 30 ? '--force-queryable' : ''} -r #{output}") if options[:api_level]
  sh("chmod +x #{output}") if options[:chmod]
end
